/*
 * @Author: byAcya xiaoxianbin@4399inc.com
 * @Date: 2025-02-11 10:52:13
 * @LastEditors: byAcya xiaoxianbin@4399inc.com
 * @LastEditTime: 2025-02-11 14:03:37
 * @FilePath: \CocosFramework\assets\script\core\pool\ObjectPoolMgr.ts
 * @Description: 对象池管理
 */
import { instantiate, Node, NodePool, Prefab } from 'cc';
import Instance from '../utils/Instance';

export interface IObjectPoolMgr {
    create(name: string, prefab: Prefab, initialSize: number, maxSize?: number): void; //创建对象池
    get(name: string): Node | null;
    put(name: string, node: Node): void;
    autoExpand(name: string, prefab: Prefab, initialSize: number, maxSize?: number): void;
    clear(name: string): void;
    getAllPoolNames(): string[];
    getSize(name: string): number; //对象池大小
}

export class ObjectPoolMgr implements IObjectPoolMgr {
    protected pools: Map<string, NodePool> = new Map();
    public static getInstance(): ObjectPoolMgr {
        return Instance.get<ObjectPoolMgr>(ObjectPoolMgr);
    }

    create(name: string, prefab: Prefab, initialSize: number, maxSize?: number): void {
        if (!this.pools.has(name)) {
            const pool = new NodePool();
            this.pools.set(name, pool);
            new Array(initialSize).fill(1).forEach((v) => {
                pool.put(instantiate(prefab));
            });
        }
    }
    get(name: string): Node | null {
        const pool = this.pools.get(name);
        if (pool && pool.size()) {
            const node = pool.get();
            node.active = true;
            return node;
        }
        return null;
    }
    put(name: string, node: Node): void {
        const pool = this.pools.get(name);
        if (pool) {
            node.active = false;
            pool.put(node);
        }
    }
    autoExpand(name: string, prefab: Prefab, initialSize: number, maxSize?: number): void {
        const pool = this.pools.get(name);
        if (!pool) {
            this.create(name, prefab, initialSize, maxSize);
        } else if (pool.size() < maxSize) {
            new Array(initialSize).fill(1).forEach((v) => {
                pool.put(instantiate(prefab));
            });
        }
    }
    clear(name: string): void {
        const pool = this.pools.get(name);
        if (pool) {
            pool.clear();
            this.pools.delete(name);
        }
    }
    getAllPoolNames(): string[] {
        const names: string[] = [];
        for (const key of this.pools.keys()) {
            names.push(key);
        }
        return names;
    }
    getSize(name: string): number {
        const pool = this.pools.get(name);
        if (pool) {
            return pool.size();
        }
        return 0;
    }
}
